home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-02 / biged.zip / BIGED.IN1 < prev    next >
Text File  |  1990-12-12  |  50KB  |  1,838 lines

  1.  
  2. {***************************************}
  3. {*           BIGED.IN1  1.03           *}
  4. {*         (part of BIGED.PAS)         *}
  5. {***************************************}
  6.  
  7.   function BigEditor.beOfsWhite(P : LinePtr) : Byte;
  8.   var B : Byte;
  9.   begin
  10.     beOfsWhite := 0;
  11.     if P^.lnLen = 0 then exit;
  12.     B := 0;
  13.     while (B <= Byte(P^.St^[0])) and (P^.St^[B+1] = ' ') do
  14.       Inc(B);
  15.     beOfsWhite := B;
  16.   end;
  17.  
  18.   procedure BigEditor.beResetSplit;
  19.   var
  20.     I : Integer;
  21.   begin
  22.     CurTopIdx := EList.Num(CurTop);
  23.     I := CurLineOfs;
  24.     if I > Height-1 then
  25.       I := Height-1;
  26.     CurLine := CurTop;
  27.     CurLineOfs := 0;
  28.     beLineDown(I);
  29.   end;
  30.  
  31.   procedure BigEditor.beReAlign;
  32.   var
  33.     N : LinePtr;
  34.     I : Integer;
  35.   begin
  36.     CurTopIdx := EList.Num(CurTop);
  37.     N := CurTop;
  38.     I := 0;
  39.     while (I < Height-1) and (CurLine <> N) do begin
  40.       N := LinePtr(N^.dlNext);
  41.       Inc(I);
  42.     end;
  43.     if I = Height-1 then
  44.       CurLine := LinePtr(N^.dlPrev);
  45.     CurLineOfs := I;
  46.   end;
  47.  
  48.   procedure BigEditor.beRealignDown;
  49.   var
  50.     N : LinePtr;
  51.     I : Integer;
  52.   begin
  53.     CurTopIdx := EList.Num(CurTop);
  54.     N := CurTop;
  55.     I := 0;
  56.     while (N^.dlNext <> nil) and (CurLine <> N) do begin
  57.       N := LinePtr(N^.dlNext);
  58.       Inc(I);
  59.       if I > Height-1 then begin
  60.         CurTop := LinePtr(CurTop^.dlNext);
  61.         Inc(CurTopIdx);
  62.       end;
  63.     end;
  64.     if I >= Height-1 then
  65.       CurLineOfs := Height-1
  66.     else
  67.       CurLineOfs := I;
  68.   end;
  69.  
  70.   procedure BigEditor.beDeleteLinePrim(P : LinePtr);
  71.   var Q,T : LinePtr;
  72.       IsBetween : Boolean;
  73.       InVis : Boolean;
  74.       W : Integer;
  75.   begin
  76.     T := P;
  77.     with EList do begin
  78.       if T^.dlNext = NIL then
  79.         T^.lnUpdate('')
  80.       else begin
  81.         if T = CurTop then begin
  82.           CurTop := LinePtr(CurTop^.dlNext);
  83.           if T = CurLine then
  84.             CurLine := LinePtr(CurLine^.dlNext)
  85.           else
  86.             Dec(CurLineOfs);
  87.         end
  88.         else if T = CurLine then
  89.           CurLine := LinePtr(CurLine^.dlNext)
  90.         else begin
  91.           IsBetween := False;
  92.           InVis := False;
  93.           Q := CurTop;
  94.           for W := 1 to Height do begin
  95.             if Q = T then InVis := True;
  96.             if (Q = CurLine) and (InVis) then IsBetween := True;
  97.  
  98.             if Q <> NIL then
  99.               Q := LinePtr(Next(Q));
  100.           end;
  101.           if IsBetween then
  102.             Dec(CurLineOfs);
  103.         end;
  104.         beLineDeleted(T);
  105.         EList.Delete(T);
  106.       end;
  107.     end;
  108.     SetLongFlag(beOptions,beModified);
  109.     beForceRedraw := True;
  110.   end;
  111.  
  112.  
  113.   procedure BigEditor.beCharsInserted(LP : LinePtr; Count : Integer);
  114.   var I : Integer;
  115.  
  116.     procedure FixMarker(var MR : MarkerRec; IsEnd,IsTextMarker : Boolean);
  117.     var T : Integer;
  118.     begin
  119.       with MR do
  120.         if (Line = LP) and (Col >= COfs+XOfs) then begin
  121.           T := Col;
  122.           if (IsTextMarker) or
  123.              ((IsEnd) and (T+1 >= COfs+XOfs)) or
  124.              (T > COfs+XOfs) then
  125.             Inc(T, Count);
  126.  
  127.           if T < COfs+XOfs then
  128.             Col := COfs+XOfs
  129.           else
  130.             Col := T;
  131.         end;
  132.     end;
  133.  
  134.   begin
  135.     if LP = BkTop.Line then FixMarker(BkTop,False,False);
  136.     if LP = BkBot.Line then FixMarker(BkBot,True,False);
  137.     beCheckBlock;
  138.     if NOT beOptionsAreOn(beBlockOK) then
  139.       beOptionsOff(beBlockOn);
  140.  
  141.     if MarkerFlags <> 0 then
  142.       for I := 0 to MaxMarker do
  143.         if LP = Markers[i].Line then
  144.           FixMarker(Markers[i],False,True);
  145.   end;
  146.  
  147.   procedure BigEditor.beLineDeleted(P : LinePtr);
  148.   var I : Integer;
  149.   begin
  150.     if P = BkTop.Line then begin
  151.       if P = BkBot.Line then begin
  152.         beResetMarkers(False);
  153.         beOptionsOff(beBlockOn);
  154.       end
  155.       else begin
  156.         IncPtr(BkTop.Line,1);
  157.         Inc(BkTop.LNum);
  158.         BkTop.Col := 1;
  159.       end;
  160.     end
  161.     else if P = BkBot.Line then begin
  162.       IncPtr(BkBot.Line,1);
  163.       Inc(BkBot.LNum);
  164.       BkBot.Col := 0;
  165.     end
  166.     else begin
  167.       I := EList.Num(P);
  168.       if I < BkTop.LNum then begin
  169.         Dec(BkTop.LNum);
  170.         Dec(BkBot.LNum);
  171.       end
  172.       else if I < BkBot.LNum then
  173.         Dec(BkBot.LNum);
  174.     end;
  175.     beCheckBlock;
  176.     if beOptionsAreOn(beBlockOK) then begin
  177.       beClearBlocking;
  178.       beConnectMarks;
  179.     end;
  180.  
  181.     if MarkerFlags <> 0 then
  182.       for I := 0 to MaxMarker do
  183.         if Markers[i].Line = P then
  184.           Markers[i].Line := NIL;
  185.  
  186.     SetLongFlag(beOptions,beModified);
  187.     beForceRedraw := True;
  188.   end;
  189.  
  190.   procedure BigEditor.beBreakLine(At : Integer);
  191.   var L : LinePtr;
  192.       P : LinePtr;
  193.       I : Integer;
  194.       B : Byte;
  195.  
  196.     procedure FixMarker(var MR : MarkerRec; IsEnd : Boolean);
  197.     begin
  198.       with MR do if Line <> nil then
  199.         if ((IsEnd) and (Col <= At)) or
  200.            (Col >= At) then begin
  201.           IncPtr(Line,1);
  202.           Inc(LNum);
  203.           Col := Col-At+1;
  204.         end;
  205.     end;
  206.  
  207.   begin
  208.     Tmp := '';
  209.     B := 1;
  210.     P := CurLine;
  211.  
  212.       {place our new line in the stream}
  213.     New(L,Init(''));
  214.     EList.Place(L,P);
  215.       {fixup blocking}
  216.     if P = BkTop.Line then begin
  217.       FixMarker(BkTop,False);
  218.       if P = BkBot.Line then
  219.         FixMarker(BkBot,True);
  220.     end
  221.     else if P = BkBot.Line then
  222.       FixMarker(BkBot,True)
  223.     else begin
  224.       I := CurTopIdx+CurLineOfs;
  225.       if I < BkTop.LNum then begin
  226.         Inc(BkTop.LNum);
  227.         Inc(BkBot.LNum);
  228.       end
  229.       else if I < BkBot.LNum then
  230.         Inc(BkBot.LNum);
  231.     end;
  232.  
  233.     beCheckBlock;
  234.     if beOptionsAreOn(beBlockOK) then begin
  235.       beClearBlocking;
  236.       beConnectMarks;
  237.     end;
  238.     if MarkerFlags <> 0 then
  239.       for I := 1 to MaxMarker do
  240.         if Markers[i].Line = P then
  241.           FixMarker(Markers[i],False);
  242.  
  243.     if At <= P^.lnLen then begin
  244.         {split the line}
  245.       Tmp := Copy(Current,At,Length(Current));
  246.       Delete(Current,At,Length(Current));
  247.       P^.lnUpdate(Current);
  248.     end;
  249.  
  250.       {add padding if nessessary}
  251.     if beOptionsAreOn(beIndent) then begin
  252.       B := beOfsWhite(P);
  253.       if B > 0 then
  254.         Insert(CharStr(' ',B),Tmp,1);
  255.     end;
  256.  
  257.     L^.lnUpdate(Tmp);
  258.     beLineDown(1);
  259.     beCursorHome;
  260.     beCursorRight(B);
  261.     beCharsInserted(CurLine,B);
  262.     SetLongFlag(beOptions,beModified);
  263.     beForceRedraw := True;
  264.   end;
  265.  
  266.   procedure BigEditor.beWrapLine;
  267.   var L : LinePtr;
  268.       P : LinePtr;
  269.       I : Integer;
  270.       B : Byte;
  271.  
  272.     procedure FixMarker(var MR : MarkerRec; At : Integer);
  273.     begin
  274.       with MR do if Line <> nil then
  275.         if Col >= At then begin
  276.           IncPtr(Line,1);
  277.           Inc(LNum);
  278.           Col := Col-At+1;
  279.         end;
  280.     end;
  281.  
  282.   begin
  283.     Tmp := '';
  284.     B := 1;
  285.     P := CurLine;
  286.  
  287.       {place our new line in the stream}
  288.     New(L,Init(''));
  289.     EList.Place(L,P);
  290.     WordWrap(Current,Current,Tmp,Margin,False);
  291.     P^.lnUpdate(Current);
  292.  
  293.       {fixup blocking}
  294.     if P = BkTop.Line then begin
  295.       FixMarker(BkTop,Length(Current)+1);
  296.       if P = BkBot.Line then
  297.         FixMarker(BkBot,Length(Current)+1);
  298.     end
  299.     else if P = BkBot.Line then
  300.       FixMarker(BkBot,Length(Current)+1)
  301.     else begin
  302.       I := CurTopIdx+CurLineOfs;
  303.       if I < BkTop.LNum then begin
  304.         Inc(BkTop.LNum);
  305.         Inc(BkBot.LNum);
  306.       end
  307.       else if I < BkBot.LNum then
  308.         Inc(BkBot.LNum);
  309.     end;
  310.  
  311.     beCheckBlock;
  312.     if beOptionsAreOn(beBlockOK) then begin
  313.       beClearBlocking;
  314.       beConnectMarks;
  315.     end;
  316.     if MarkerFlags <> 0 then
  317.       for I := 1 to MaxMarker do
  318.         if Markers[i].Line = P then
  319.           FixMarker(Markers[i],Length(Current)+1);
  320.  
  321.       {add padding if nessessary}
  322.     if beOptionsAreOn(beIndent) then begin
  323.       Tmp := Trim(Tmp);
  324.       B := beOfsWhite(P);
  325.       if B > 0 then
  326.         Insert(CharStr(' ',B),Tmp,1);
  327.     end;
  328.  
  329.     L^.lnUpdate(Tmp);
  330.     beLineDown(1);
  331.     beCursorHome;
  332.     beCursorRight(Length(Tmp));
  333.     beCharsInserted(CurLine,Length(Tmp));
  334.     SetLongFlag(beOptions,beModified);
  335.     beForceRedraw := True;
  336.   end;
  337.  
  338.   procedure BigEditor.beJoinLines(LP : LinePtr);
  339.   var L,P : LinePtr;
  340.       I,J : Integer;
  341.  
  342.     procedure FixMarker(var MR : MarkerRec; PrevLen : Integer);
  343.     begin
  344.       with MR do if Line <> NIL then begin
  345.         DecPtr(Line,1);
  346.         Dec(LNum);
  347.         Col := Col + PrevLen;
  348.       end;
  349.     end;
  350.  
  351.   begin
  352.     P := LP;
  353.     L := LinePtr(P^.dlNext);
  354.     if L = NIL then exit;
  355.     J := P^.lnLen;
  356.     P^.lnUpdate(P^.lnReturn+L^.lnReturn);
  357.  
  358.       {fixup blocking}
  359.     if P = BkTop.Line then begin
  360.       FixMarker(BkTop,J);
  361.       if P = BkBot.Line then
  362.         FixMarker(BkBot,J);
  363.     end
  364.     else if P = BkBot.Line then
  365.       FixMarker(BkBot,J)
  366.     else begin
  367.       I := EList.Num(P);
  368.       if I < BkTop.LNum then begin
  369.         Dec(BkTop.LNum);
  370.         Dec(BkBot.LNum);
  371.       end
  372.       else if I < BkBot.LNum then
  373.         Dec(BkBot.LNum);
  374.     end;
  375.  
  376.     beCheckBlock;
  377.     if beOptionsAreOn(beBlockOK) then begin
  378.       beClearBlocking;
  379.       beConnectMarks;
  380.     end;
  381.     if MarkerFlags <> 0 then
  382.       for I := 0 to MaxMarker do
  383.         if Markers[i].Line = L then
  384.           FixMarker(Markers[i],J);
  385.  
  386.     EList.Delete(L);
  387.     SetLongFlag(beOptions,beModified);
  388.     beForceRedraw := True;
  389.   end;
  390.  
  391.   procedure BigEditor.beTabOver;
  392.   var P : LinePtr;
  393.       N,W : Integer;
  394.   begin
  395.     if beOptionsAreOn(beSmartTabs) then begin
  396.       W := COfs+XOfs;
  397.       P := CurLine;
  398.       DecPtr(P,1);
  399.       if (P = NIL) or (W > P^.lnLen) then
  400.         IncPtr(P,2);
  401.       if (P <> NIL) and (W <= P^.lnLen) then begin
  402.         Tmp := P^.lnReturn;
  403.         N := W;
  404.         while (W <= Length(Tmp)) and (Tmp[w] <> ' ') do
  405.           Inc(W);
  406.         while (W <= Length(Tmp)) and (Tmp[w] = ' ') do
  407.           Inc(W);
  408.         if W > N then begin
  409.           if N <= Length(Current) then begin
  410.             Insert(CharStr(' ',W-N),Current,N);
  411.             CurLine^.lnUpdate(Current);
  412.             beCharsInserted(CurLine,W-N);
  413.             SetLongFlag(beOptions,beModified);
  414.           end;
  415.           beCursorRight(W-N);
  416.         end;
  417.       end;
  418.     end
  419.     else if beDefTabDelta > 0 then begin
  420.       W := beDefTabDelta - ((COfs+XOfs) mod beDefTabDelta);
  421.       if W = 0 then W := beDefTabDelta;
  422.       if COfs+XOfs <= Length(Current) then begin
  423.         Insert(CharStr(' ',W),Current,COfs+XOfs);
  424.         CurLine^.lnUpdate(Current);
  425.         beCharsInserted(CurLine,W);
  426.         SetLongFlag(beOptions,beModified);
  427.       end;
  428.       beCursorRight(W);
  429.     end;
  430.   end;
  431.  
  432.   procedure BigEditor.beInsertChar(C : Char);
  433.     {insert a character into the stream}
  434.   var W : Byte absolute Current;
  435.       B,L : Byte;
  436.       S : String;
  437.       P : LinePtr;
  438.   begin
  439.     if COfs+XOfs >= 255 then exit;
  440.     if W < (COfs+XOfs) then begin
  441.       Current := Pad(Current,COfs+XOfs-1) + C;
  442.       beCharsInserted(CurLine,COfs+XOfs-W);
  443.     end
  444.     else if LongFlagIsSet(beOptions,beInsert) then begin
  445.       Insert(C,Current,COfs+XOfs);
  446.       beCharsInserted(CurLine,1);
  447.     end
  448.     else
  449.       Current[COfs+XOfs] := C;
  450.     CurLine^.lnUpdate(Current);
  451.     beCursorRight(1);
  452.     SetLongFlag(beOptions,beModified);
  453.  
  454.       {if we're wrapping, do so here}
  455.     if (beOptionsAreOn(beWordWrap)) and
  456.        (COfs+XOfs > Margin+1) and
  457.        (C <> ' ') then
  458.       beWrapLine;
  459.   end;
  460.  
  461.   procedure BigEditor.beNewLine(MoveDown : Boolean);
  462.     {-insert a new line below the current}
  463.   var
  464.     L : LinePtr;
  465.     I : Integer;
  466.   begin
  467.     if NOT LongFlagIsSet(beOptions,beInsert) then begin
  468.       beLineDown(1);
  469.       COfs := 1;
  470.       XOfs := 0;
  471.     end
  472.     else if NOT(MoveDown) then begin
  473.       I := COfs+XOfs;
  474.       beBreakLine(CurLine^.lnLen+1);
  475.       beLineUp(1);
  476.       beCursorHome;
  477.       beCursorRight(I-1);
  478.     end
  479.     else
  480.       beBreakLine(COfs+XOfs);
  481.   end;
  482.  
  483.   procedure BigEditor.beBackspace;
  484.    {-backspace over the previous character}
  485.   var
  486.     I : Integer;
  487.   begin
  488.     if (COfs+XOfs > 1) then begin
  489.       if (COfs+XOfs) <= (CurLine^.lnLen+1) then begin
  490.         System.Delete(Current,COfs+XOfs-1,1);
  491.         CurLine^.lnUpdate(Current);
  492.         beCharsInserted(CurLine, -1);
  493.         SetLongFlag(beOptions,beModified);
  494.       end;
  495.       beCursorLeft(1);
  496.     end
  497.     else if CurLine^.dlPrev <> NIL then begin
  498.       beLineUp(1);
  499.       I := CurLine^.lnLen;
  500.       beJoinLines(CurLine);
  501.       beCursorHome;
  502.       beCursorRight(I);
  503.       beForceRedraw := True;
  504.       SetLongFlag(beOptions,beModified);
  505.     end;
  506.   end;
  507.  
  508.   procedure BigEditor.beDeleteCharAtCursor;
  509.     {-delete the current character}
  510.   begin
  511.     if (COfs+XOfs) <= Length(Current) then begin
  512.       System.Delete(Current,COfs+XOfs,1);
  513.       CurLine^.lnUpdate(Current);
  514.       beCharsInserted(CurLine,-1);
  515.       SetLongFlag(beOptions,beModified);
  516.     end
  517.     else if beOptionsAreOn(beDeleteJoins) then begin
  518.       if Length(Current) < COfs+XOfs-1 then
  519.         CurLine^.lnUpdate(Pad(Current,COfs+XOfs-1));
  520.       beJoinLines(CurLine);
  521.       SetLongFlag(beOptions,beModified);
  522.       beForceRedraw := True;
  523.     end;
  524.   end;
  525.  
  526.   procedure BigEditor.beWordLeft;
  527.     {-jump to the start of the previous word}
  528.   var W : Byte absolute Current;
  529.       X,N : Integer;
  530.       Cl : CharClass;
  531.   begin
  532.     if COfs+XOfs > 1 then begin
  533.       if W < (COfs+XOfs) then begin
  534.         if COfs+XOfs{W} >= WinWidth then begin
  535.           COfs := WinWidth;
  536.           XOfs := W - WinWidth + 1;
  537.           beForceRedraw := True;
  538.         end
  539.         else begin
  540.           COfs := W+1;
  541.           XOfs := 0;
  542.         end;
  543.       end;
  544.       X := COfs+XOfs;
  545.       N := X;
  546.       while (X > 1) and (GetClass(Current[x-1]) <> Alpha) do
  547.         Dec(x);
  548.       while (X > 1) and (GetClass(Current[x-1]) = Alpha) do
  549.         Dec(x);
  550.       beCursorLeft(N-X);
  551.     end
  552.     else if CurLine^.dlPrev <> NIL then begin
  553.       beLineUp(1);
  554.       beCursorEOL;
  555.     end;
  556.   end;
  557.  
  558.   procedure BigEditor.beWordRight;
  559.     {-jump to the start of the next word}
  560.   var W : Byte Absolute Current;
  561.       N,X : Integer;
  562.   begin
  563.     if (COfs+XOfs > W) and (CurLine^.dlNext <> NIL) then begin
  564.       beLineDown(1);
  565.       beCursorHome;
  566.     end
  567.     else begin
  568.       X := COfs+XOfs;
  569.       N := X;
  570.       while (X <= W) and NOT(Current[x] in beWordDelims) do
  571.         Inc(X);
  572.       while (X <= W) and (Current[x] in beWordDelims) do
  573.         Inc(X);
  574.       beCursorRight(X-N);
  575.     end;
  576.   end;
  577.  
  578.   procedure BigEditor.beDeleteWordRight;
  579.     {-delete the current word}
  580.   var
  581.     P : LinePtr;
  582.     W,X,I : Integer;
  583.     Sl : Byte absolute Current;
  584.     ChClass : CharClass;
  585.   begin
  586.     X := XOfs+COfs;
  587.     if (Sl < X) and (CurLine^.dlNext <> NIL) then
  588.       beJoinLines(CurLine)
  589.     else begin
  590.       W := X;
  591.       if Current[w] <> ' ' then begin
  592.         ChClass := GetClass(Current[w]);
  593.         while (W <= Sl) and (GetClass(Current[w]) = ChClass) do
  594.           Inc(W);
  595.       end;
  596.       while (W <= Sl) and (GetClass(Current[w]) = Blank) do
  597.         Inc(W);
  598.  
  599.       I := W-X;
  600.       if W > X then begin
  601.         System.Delete(Current,X,I);
  602.         CurLine^.lnUpdate(Current);
  603.         beCharsInserted(CurLine,-I);
  604.         SetLongFlag(beOptions,beModified);
  605.       end;
  606.     end;
  607.   end;
  608.  
  609.   procedure BigEditor.beDeleteToEndOfLine;
  610.     {-delete the rest of the current line}
  611.   var I : Integer;
  612.   begin
  613.     if (COfs+XOfs) <= Length(Current) then begin
  614.       I := Length(Current) - (COfs+XOfs);
  615.       System.Delete(Current,COfs+XOfs,Length(Current));
  616.       CurLine^.lnUpdate(Current);
  617.       beCharsInserted(CurLine,-I);
  618.       SetLongFlag(beOptions,beModified);
  619.       beForceRedraw := True;
  620.     end;
  621.   end;
  622.  
  623.   procedure BigEditor.beSaveStreamState(var S : StreamStateRec;
  624.                                         SaveBlocking : Boolean);
  625.   begin
  626.     with S do begin
  627.       SaveCurTopIdx := CurTopIdx;
  628.       SaveCurLineOfs := CurLineOfs;
  629.       SaveCOfs := COfs;
  630.       SaveXOfs := XOfs;
  631.       SaveFlags := beOptions;
  632.       if SaveBlocking then begin
  633.         SaveBkTop := BkTop;
  634.         SaveBkBot := BkBot;
  635.         SaveMarkers := Markers;
  636.       end
  637.       else begin
  638.         FillChar(SaveBkTop,SizeOf(SaveBkTop),0);
  639.         SaveBkBot := SaveBkBot;
  640.         FillChar(SaveMarkers,SizeOf(SaveMarkers),0);
  641.       end;
  642.     end;
  643.   end;
  644.  
  645.   procedure BigEditor.beRestoreStreamState(var S : StreamStateRec;
  646.                                            RestoreBlocking : Boolean);
  647.   var I : Integer;
  648.   begin
  649.     beResetLineList;
  650.     with S do begin
  651.       CurTop := LinePtr(EList.Nth(SaveCurTopIdx));
  652.       CurLine := CurTop;
  653.       CurTopIdx := SaveCurTopIdx;
  654.       CurLineOfs := SaveCurLineOfs;
  655.       I := 0;
  656.       while I <> CurLineOfs do begin
  657.         CurLine := LinePtr(CurLine^.dlNext);
  658.         Inc(I);
  659.       end;
  660.       COfs := SaveCOfs;
  661.       XOfs := SaveXOfs;
  662.       beOptions := beOptions or (SaveFlags and not BadBigEdOptions);
  663.       if RestoreBlocking then begin
  664.         BkTop := SaveBkTop;
  665.         BkTop.Line := LinePtr(EList.Nth(BkTop.LNum));
  666.         BkBot := SaveBkBot;
  667.         BkBot.Line := LinePtr(EList.Nth(BkBot.LNum));
  668.         beCheckBlock;
  669.         if beOptionsAreOn(beBlockOK) then begin
  670.           beClearBlocking;
  671.           beConnectMarks;
  672.           beOptionsOn(beBlockOn);
  673.         end;
  674.         Markers := SaveMarkers;
  675.         for I := 0 to MaxMarker do
  676.           Markers[i].Line := LinePtr(EList.Nth(Markers[i].LNum));
  677.       end;
  678.     end;
  679.     beForceRedraw := True;
  680.   end;
  681.  
  682. {----------------------- Block-oriented operations -------------------------}
  683.  
  684.   procedure BigEditor.beClearBlocking;
  685.   var P : LinePtr;
  686.   begin
  687.     with EList do begin
  688.       P := LinePtr(Head);
  689.       while P <> NIL do begin
  690.         P^.lnFlagsOff(IsBlocked);
  691.         P := LinePtr(P^.dlNext);
  692.       end;
  693.       ClearLongFlag(beOptions,beBlockOK);
  694.     end;
  695.   end;
  696.  
  697.   procedure BigEditor.beConnectMarks;
  698.   var P : LinePtr;
  699.   begin
  700.     P := BkTop.Line;
  701.     if P = NIL then
  702.       beClearBlocking
  703.     else if BkBot.Line <> NIL then begin
  704.       P^.lnFlagsOn(IsBlocked);
  705.       while (P <> nil) and (P <> BkBot.Line) do begin
  706.         P^.lnFlagsOn(IsBlocked);
  707.         P := LinePtr(P^.dlNext);
  708.       end;
  709.       if P <> nil then begin
  710.         P^.lnFlagsOn(IsBlocked);
  711.         SetLongFlag(beOptions,beBlockOK);
  712.       end
  713.       else
  714.         beClearBlocking;
  715.     end;
  716.   end;
  717.  
  718.   function BigEditor.beLineInBlock(P : LinePtr) : Boolean;
  719.   var N : LinePtr;
  720.   begin
  721.     beLineInBlock := True;
  722.     N := BkTop.Line;
  723.     while (N <> nil) and (N <> BkBot.Line) do begin
  724.       if N = P then exit;
  725.       N := LinePtr(N^.dlNext);
  726.     end;
  727.     beLineInBlock := (P = BkBot.Line);
  728.   end;
  729.  
  730.   procedure BigEditor.beSetBkTop;
  731.   begin
  732.     with BkTop do begin
  733.       Line := CurLine;
  734.       LNum := CurTopIdx+CurLineOfs;
  735.       Col := COfs+XOfs;
  736.     end;
  737.     beCheckBlock;
  738.     if beOptionsAreOn(beBlockOK) then begin
  739.       beClearBlocking;
  740.       beConnectMarks;
  741.       beOptionsOn(beBlockOn);
  742.     end
  743.     else beOptionsOff(beBlockOn);
  744.     beForceRedraw := True;
  745.   end;
  746.  
  747.   procedure BigEditor.beSetBkBot;
  748.   begin
  749.     with BkBot do begin
  750.       Line := CurLine;
  751.       LNum := CurTopIdx+CurLineOfs;
  752.       Col := Pred(COfs+XOfs);
  753.     end;
  754.     beCheckBlock;
  755.     if beOptionsAreOn(beBlockOK) then begin
  756.       beClearBlocking;
  757.       beConnectMarks;
  758.       beOptionsOn(beBlockOn);
  759.     end
  760.     else beOptionsOff(beBlockOn);
  761.     beForceRedraw := True;
  762.   end;
  763.  
  764.   procedure BigEditor.beCheckBlock;
  765.   var P : LinePtr;
  766.   begin
  767.     ClearLongFlag(beOptions,beBlockOK);
  768.       {if no markers defined, exit}
  769.     if (BkTop.Line = NIL) or (BkBot.Line = NIL) then exit;
  770.       {if same line but mismatched columns, exit}
  771.     P := BkTop.Line;
  772.     if (P = BkBot.Line) then
  773.       if BkTop.Col >= BkBot.Col then exit;
  774.       {scan forward, looking for BkBot}
  775.     with EList do while P <> NIL do begin
  776.       if P = BkBot.Line then begin
  777.         SetLongFlag(beOptions,beBlockOK);
  778.         exit;
  779.       end;
  780.       P := LinePtr(Next(P));
  781.     end;
  782.   end;
  783.  
  784.   function BigEditor.beStoreBlock(var ToList : LineList) : Boolean;
  785.   label Skip;
  786.   var P,N : LinePtr;
  787.   begin
  788.     beStoreBlock := False;
  789.     beCheckBlock;
  790.     if (NOT(beOptionsAreOn(beBlockOK))) or
  791.        (NOT(beOptionsAreOn(beBlockOn))) then exit;
  792.     SBkTop := BkTop;
  793.     SBkBot := BkBot;
  794.     ToList.Clean;
  795.     P := BkTop.Line;
  796.  
  797.     if BkTop.Line = BkBot.Line then begin
  798.       Tmp := Copy(P^.lnReturn,BkTop.Col,BkBot.Col-BkTop.Col+1);
  799.       New(N,Init(Tmp));
  800.       if N = NIL then goto Skip;
  801.       ToList.Append(N);
  802.       beStoreBlock := True;
  803.       exit;
  804.     end
  805.     else begin
  806.       Tmp := Copy(P^.lnReturn,BkTop.Col,P^.lnLen);
  807.       New(N,Init(Tmp));
  808.       if N = NIL then goto Skip;
  809.       ToList.Append(N);
  810.  
  811.       P := LinePtr(EList.Next(P));
  812.       while P <> BkBot.Line do begin
  813.         New(N,Init(P^.lnReturn));
  814.         if N = NIL then goto Skip;
  815.         ToList.Append(N);
  816.         P := LinePtr(EList.Next(P));
  817.       end;
  818.  
  819.       Tmp := Copy(BkBot.Line^.lnReturn,1,BkBot.Col);
  820.       if TrimLead(Tmp) = '' then Tmp := '';
  821.       New(N,Init(Tmp));
  822.       if N = NIL then goto Skip;
  823.       ToList.Append(N);
  824.       beStoreBlock := True;
  825.       exit;
  826.     end;
  827. Skip:
  828.     GotError(epNonFatal+ecOutofMemory,'Out of memory');
  829.     ToList.Clean;
  830.   end;
  831.  
  832.   procedure BigEditor.beCopyBlock;
  833.   var N,O,P : LinePtr;
  834.       S : String;
  835.   begin
  836.     beCheckBlock;
  837.     if (NOT(beOptionsAreOn(beBlockOK))) or
  838.        (NOT(beOptionsAreOn(beBlockOn))) then exit;
  839.     SBkTop := BkTop;
  840.     SBkBot := BkBot;
  841.  
  842.     if BkTop.Line = BkBot.Line then begin
  843.       S := Copy(BkTop.Line^.St^,BkTop.Col,BkBot.Col-BkTop.Col+1);
  844.       Tmp := CurLine^.St^;
  845.       if COfs+XOfs > Length(Tmp) then
  846.         Tmp := Pad(Tmp,COfs+XOfs-1) + S
  847.       else
  848.         Insert(S,Tmp,COfs+XOfs);
  849.       CurLine^.lnUpdate(Tmp);
  850.  
  851.         {update blocking}
  852.       BkTop.Line^.lnFlagsOff(IsBlocked);
  853.       BkTop.Line := CurLine;
  854.       BkTop.LNum := CurTopIdx+CurLineOfs;
  855.       BkTop.Col := COfs+XOfs;
  856.       BkBot := BkTop;
  857.       BkBot.Col := Min(CurLine^.lnLen,COfs+XOfs+Length(S)-1);
  858.       CurLine^.lnFlagsOn(IsBlocked);
  859.     end
  860.     else begin
  861.       N := BkTop.Line;
  862.       P := CurLine;
  863.       Tmp := P^.lnReturn;
  864.         {if needed, split the current line}
  865.       if COfs+XOfs <= Length(Tmp) then begin
  866.         S := Copy(Tmp,COfs+XOfs,Length(Tmp));
  867.         Delete(Tmp,COfs+XOfs,Length(Tmp));
  868.       end
  869.       else begin
  870.         if COfs+XOfs-1 > Length(Tmp) then
  871.           Tmp := Pad(Tmp,COfs+XOfs-1);
  872.         S := '';
  873.       end;
  874.  
  875.         {set BlockTop to our new starting point}
  876.       BkTop.Line := P;
  877.       BkTop.LNum := CurTopIdx+CurLineOfs;
  878.       BkBot.LNum := BkTop.LNum;
  879.       BkTop.Col := COfs+XOfs;
  880.  
  881.         {walk the list, inserting lines}
  882.       Tmp := P^.St^ + N^.St^;
  883.       P^.lnUpdate(Tmp);
  884.       N^.lnFlagsOff(IsBlocked);
  885.       N := LinePtr(N^.dlNext);
  886.       while N <> BkBot.Line do begin
  887.         New(O,Init(N^.St^));
  888.         O^.lnFlagsOn(IsBlocked);
  889.         EList.Place(O,P);
  890.         P := LinePtr(P^.dlNext);
  891.         N^.lnFlagsOff(IsBlocked);
  892.         N := LinePtr(N^.dlNext);
  893.         Inc(BkBot.LNum);
  894.       end;
  895.  
  896.         {fixup the last line}
  897.       Tmp := Copy(N^.lnReturn,1,BkBot.Col);
  898.       N^.lnFlagsOff(IsBlocked);
  899.       BkBot.Col := Length(Tmp);
  900.       if S <> '' then Tmp := Tmp + S;
  901.       New(O,Init(Tmp));
  902.       O^.lnFlagsOn(IsBlocked);
  903.       EList.Place(O,P);
  904.       P := LinePtr(P^.dlNext);
  905.       Inc(BkBot.LNum);
  906.       BkBot.Line := P;
  907.       BkTop.Line^.lnFlagsOn(IsBlocked);
  908.     end;
  909.     SetLongFlag(beOptions,beBlockOn);
  910.     SetLongFlag(beOptions,beModified);
  911.     beForceRedraw := True;
  912.   end;
  913.  
  914.   procedure BigEditor.beMoveBlock;
  915.   var N,O,P,SP : LinePtr;
  916.       S,T : String;
  917.   begin
  918.     beCheckBlock;
  919.     if (NOT(beOptionsAreOn(beBlockOK))) or
  920.        (NOT(beOptionsAreOn(beBlockOn))) then exit;
  921.     SBkTop := BkTop;
  922.     SBkBot := BkBot;
  923.  
  924.     if BkTop.Line = BkBot.Line then begin
  925.       Tmp := BkTop.Line^.lnReturn;
  926.       S := Copy(Tmp,BkTop.Col,BkBot.Col-BkTop.Col+1);
  927.       Delete(Tmp,BkTop.Col,BkBot.Col-BkTop.Col+1);
  928.       BkTop.Line^.lnUpdate(Tmp);
  929.       Tmp := CurLine^.St^;
  930.       if COfs+XOfs > Length(Tmp) then
  931.         Tmp := Pad(Tmp,COfs+XOfs-1) + S
  932.       else
  933.         Insert(S,Tmp,COfs+XOfs);
  934.       CurLine^.lnUpdate(Tmp);
  935.  
  936.         {update blocking}
  937.       BkTop.Line^.lnFlagsOff(IsBlocked);
  938.       BkTop.Line := CurLine;
  939.       BkTop.LNum := CurTopIdx+CurLineOfs;
  940.       BkTop.Col := COfs+XOfs;
  941.       BkBot := BkTop;
  942.       BkBot.Col := Min(CurLine^.lnLen,COfs+XOfs+Length(S)-1);
  943.       CurLine^.lnFlagsOn(IsBlocked);
  944.     end
  945.     else begin
  946.       SP := nil;
  947.       N := BkTop.Line;
  948.       Tmp := N^.lnReturn;
  949.       T := Copy(Tmp,BkTop.Col,Length(Tmp));
  950.       Delete(Tmp,BkTop.Col,Length(Tmp));
  951.       if Tmp = '' then
  952.         SP := N
  953.       else
  954.         N^.lnUpdate(Tmp);
  955.  
  956.       P := CurLine;
  957.       Tmp := P^.lnReturn;
  958.       if COfs+XOfs <= Length(Tmp) then begin
  959.         S := Copy(Tmp,COfs+XOfs,Length(Tmp));
  960.         Delete(Tmp,COfs+XOfs,Length(Tmp));
  961.       end
  962.       else begin
  963.         if COfs+XOfs-1 > Length(Tmp) then
  964.           Tmp := Pad(Tmp,COfs+XOfs-1);
  965.         S := '';
  966.       end;
  967.  
  968.         {set BlockTop to our new starting point}
  969.       BkTop.Line := P;
  970.       BkTop.LNum := CurTopIdx+CurLineOfs;
  971.       BkBot.LNum := BkTop.LNum;
  972.       BkTop.Col := COfs+XOfs;
  973.  
  974.         {walk the list, removing at old and inserting at new location}
  975.       Tmp := P^.St^ + T;
  976.       P^.lnUpdate(Tmp);
  977.       N^.lnFlagsOff(IsBlocked);
  978.       N := LinePtr(N^.dlNext);
  979.       while N <> BkBot.Line do begin
  980.         O := N;
  981.         N := LinePtr(N^.dlNext);
  982.         EList.Remove(O);
  983.         EList.Place(O,P);
  984.         P := LinePtr(P^.dlNext);
  985.         Inc(BkBot.LNum);
  986.       end;
  987.  
  988.         {fixup the last line}
  989.       Tmp := Copy(BkBot.Line^.lnReturn,1,BkBot.Col);
  990.       BkBot.Line^.lnFlagsOff(IsBlocked);
  991.       BkBot.Col := Length(Tmp);
  992.       New(O,Init(Tmp+S));
  993.       O^.lnFlagsOn(IsBlocked);
  994.       EList.Place(O,P);
  995.       P := LinePtr(P^.dlNext);
  996.       Inc(BkBot.LNum);
  997.       Delete(Tmp,1,BkBot.Col);
  998.       BkBot.Line^.lnUpdate(Tmp);
  999.       BkBot.Line := P;
  1000.       BkTop.Line^.lnFlagsOn(IsBlocked);
  1001.       if SP <> nil then
  1002.         EList.Delete(SP);
  1003.       beResetSplit;
  1004.     end;
  1005.     SetLongFlag(beOptions,beBlockOn);
  1006.     SetLongFlag(beOptions,beModified);
  1007.     beForceRedraw := True;
  1008.   end;
  1009.  
  1010.   procedure BigEditor.beDeleteBlock;
  1011.   var S : String;
  1012.       N,P : LinePtr;
  1013.       I : Integer;
  1014.       B : Boolean;
  1015.       SvSplt : Integer;
  1016.  
  1017.     function LineInBlock(P : LinePtr) : Boolean;
  1018.     var N : LinePtr;
  1019.     begin
  1020.       LineInBlock := True;
  1021.       N := BkTop.Line;
  1022.       while (N <> LinePtr(BkBot.Line^.dlNext)) do begin
  1023.         if P = N then exit;
  1024.         N := LinePtr(N^.dlNext);
  1025.       end;
  1026.       LineInBlock := False;
  1027.     end;
  1028.  
  1029.     function BlockIsBetween : Boolean;
  1030.     var P : LinePtr;
  1031.     begin
  1032.       BlockIsBetween := True;
  1033.       P := CurTop;
  1034.       while P <> CurLine do begin
  1035.         if P = BkTop.Line then exit;
  1036.         P := LinePtr(P^.dlNext);
  1037.       end;
  1038.       BlockIsBetween := False;
  1039.     end;
  1040.  
  1041.   begin
  1042.     B := False;
  1043.     beCheckBlock;
  1044.     if (NOT(beOptionsAreOn(beBlockOK))) or
  1045.        (NOT(beOptionsAreOn(beBlockOn))) then begin
  1046.       GotError(epNonFatal+ecNoBlock,'No block defined');
  1047.       exit;
  1048.     end;
  1049.     P := BkTop.Line;
  1050.       {if a single line, handle here}
  1051.     if BkTop.Line = BkBot.Line then begin
  1052.       S := P^.lnReturn;
  1053.       Delete(S,BkTop.Col,BkBot.Col-BkTop.Col+1);
  1054.       P^.lnUpdate(S);
  1055.       P^.lnFlagsOff(IsBlocked);
  1056.       beResetMarkers(False);
  1057.       if CurLine = P then begin
  1058.         beCursorHome;
  1059.         beCursorRight(BkTop.Col-1);
  1060.       end;
  1061.     end
  1062.     else with EList do begin
  1063.       if LineInBlock(CurTop) then begin
  1064.         CurTop := BkTop.Line;
  1065.         CurTopIdx := BkTop.LNum;
  1066.         if LineInBlock(CurLine) then begin
  1067.           CurLine := CurTop;
  1068.           CurLineOfs := 0;
  1069.           beCursorHome;
  1070.           beCursorRight(BkTop.Col - 1);
  1071.         end
  1072.         else B := True;
  1073.       end
  1074.       else if LineInBlock(CurLine) then begin
  1075.         P := CurTop;
  1076.         CurLine := BkTop.Line;
  1077.         CurLineOfs := 0;
  1078.         while (P <> CurLine) and (CurLineOfs < Height-1) do begin
  1079.           Inc(CurLineOfs);
  1080.           P := LinePtr(P^.dlNext);
  1081.         end;
  1082.         beCursorHome;
  1083.         beCursorRight(BkTop.Col - 1);
  1084.       end
  1085.       else B := BlockIsBetween;
  1086.  
  1087.       P := BkTop.Line;
  1088.       S := P^.lnReturn;
  1089.       System.Delete(S,BkTop.Col,Length(S));
  1090.       P^.lnUpdate(S);
  1091.  
  1092.       P := BkBot.Line;
  1093.       S := P^.lnReturn;
  1094.       System.Delete(S,1,BkBot.Col);
  1095.       SvSplt := 1;
  1096.       P^.lnUpdate(S);
  1097.  
  1098.       P := LinePtr(BkTop.Line^.dlNext);
  1099.       while P <> BkBot.Line do begin
  1100.         Inc(SvSplt);
  1101.         EList.Delete(P);
  1102.         P := LinePtr(BkTop.Line^.dlNext);
  1103.       end;
  1104.  
  1105.       P := BkTop.Line;
  1106.       beJoinLines(P);
  1107.     end;
  1108.     beResetSplit;
  1109.     if B then
  1110.       beLineUp(SvSplt);
  1111.     beResetMarkers(False);
  1112.     ClearLongFlag(beOptions,beBlockOn+beBlockOK);
  1113.     SetLongFlag(beOptions,beModified);
  1114.     beForceRedraw := True;
  1115.   end;
  1116.  
  1117.   procedure BigEditor.beInsertBlockAtCursor(var FromList : LineList);
  1118.   var P,N,O : LinePtr;
  1119.       B : Boolean;
  1120.       S : String;
  1121.   begin
  1122.       if (FromList.Size = 0) then begin
  1123.       GotError(epNonFatal+ecNoBlock,'No block defined');
  1124.       exit;
  1125.     end;
  1126.  
  1127.     P := CurLine;
  1128.     if FromList.Head = FromList.Tail then begin
  1129.         {a partial line to insert in the current line}
  1130.       S := LinePtr(FromList.Head)^.lnReturn;
  1131.  
  1132.       Tmp := CurLine^.St^;
  1133.       if COfs+XOfs > Length(Tmp) then
  1134.         Tmp := Pad(Tmp,COfs+XOfs-1) + S
  1135.       else
  1136.         Insert(S,Tmp,COfs+XOfs);
  1137.       CurLine^.lnUpdate(Tmp);
  1138.  
  1139.         {update blocking}
  1140.       beClearBlocking;
  1141.       BkTop.Line := CurLine;
  1142.       BkTop.LNum := CurTopIdx+CurLineOfs;
  1143.       BkTop.Col := COfs+XOfs;
  1144.       BkBot := BkTop;
  1145.       BkBot.Col := Min(CurLine^.lnLen,COfs+XOfs+Length(S)-1);
  1146.       CurLine^.lnFlagsOn(IsBlocked);
  1147.     end
  1148.     else begin
  1149.       Tmp := P^.lnReturn;
  1150.         {if needed, split the current line}
  1151.       if COfs+XOfs <= Length(Tmp) then begin
  1152.         S := Copy(Tmp,COfs+XOfs,Length(Tmp));
  1153.         Delete(Tmp,COfs+XOfs,Length(Tmp));
  1154.       end
  1155.       else begin
  1156.         if COfs+XOfs-1 > Length(Tmp) then
  1157.           Tmp := Pad(Tmp,COfs+XOfs-1);
  1158.         S := '';
  1159.       end;
  1160.  
  1161.         {set BlockTop to our new starting point}
  1162.       BkTop.Line := P;
  1163.       BkTop.LNum := CurTopIdx+CurLineOfs;
  1164.       BkBot.LNum := BkTop.LNum;
  1165.       BkTop.Col := COfs+XOfs;
  1166.  
  1167.         {walk the list, inserting lines}
  1168.       N := LinePtr(FromList.Head);
  1169.       Tmp := P^.St^ + N^.St^;
  1170.       P^.lnUpdate(Tmp);
  1171.       N := LinePtr(N^.dlNext);
  1172.       while N <> NIL do begin
  1173.         New(O,Init(N^.St^));
  1174.         EList.Place(O,P);
  1175.         P := LinePtr(P^.dlNext);
  1176.         N := LinePtr(N^.dlNext);
  1177.         Inc(BkBot.LNum);
  1178.       end;
  1179.  
  1180.         {set BlockBot to our ending line}
  1181.       BkBot.Line := P;
  1182.       BkBot.Col := BkBot.Line^.lnLen;
  1183.  
  1184.         {if needed, merge in the tail of the split top line}
  1185.       if S <> '' then begin
  1186.         Tmp := P^.lnReturn;
  1187.         P^.lnUpdate(Tmp+S);
  1188.       end;
  1189.  
  1190.         {reset things}
  1191.       beClearBlocking;
  1192.       beConnectMarks;
  1193.     end;
  1194.     SetLongFlag(beOptions,beBlockOn);
  1195.     SetLongFlag(beOptions,beModified);
  1196.     beForceRedraw := True;
  1197.   end;
  1198.  
  1199.   procedure BigEditor.beReadBlock;
  1200.   var F : Text;
  1201.       FHandle : Word;
  1202.       FName : PathStr;
  1203.       P,N : LinePtr;
  1204.   begin
  1205.     FName := '';
  1206.     if not beGetFileName(epMessage+mcBlockWrite, emBlockWrite,
  1207.                          FName, True, False) then
  1208.       Exit;
  1209.     Assign(F,FName);
  1210.     Reset(F);
  1211.     if IOResult <> 0 then begin
  1212.       GotError(epNonFatal+ecFileNotFound,'File not found');
  1213.       exit;
  1214.     end
  1215.     else if HandleIsConsole(FHandle) then begin
  1216.       Close(F);  if IOResult = 0 then ;
  1217.       GotError(epNonFatal+ecNotToScreen,'Cannot read file from screen');
  1218.       exit;
  1219.     end;
  1220.  
  1221.     TmpList.Clean;
  1222.     while NOT EOF(F) do begin
  1223.       ReadLn(F,Tmp);
  1224.       if IOResult = 0 then begin
  1225.         New(P,Init(Tmp));
  1226.         if P = NIL then begin
  1227.           GotError(epNonFatal+ecOutofMemory,'Out of memory');
  1228.           Close(F);  if IOResult = 0 then ;
  1229.           exit;
  1230.         end;
  1231.         TmpList.Append(P);
  1232.       end;
  1233.     end;
  1234.       {assure block marks are not equal}
  1235.     BkTop.Line := CurTop;
  1236.     BkBot.Line := NIL;
  1237.     beInsertBlockAtCursor(TmpList);
  1238.     SetLongFlag(beOptions,beBlockOn);
  1239.     SetLongFlag(beOptions,beModified);
  1240.     beForceRedraw := True;
  1241.   end;
  1242.  
  1243.   procedure BigEditor.beWriteBlock(ToPrn : Boolean);
  1244.   var F : Text;
  1245.       FHandle : Word absolute F;
  1246.       FName : PathStr;
  1247.       I : Integer;
  1248.       P : LinePtr;
  1249.   begin
  1250.     beCheckBlock;
  1251.     if (NOT(beOptionsAreOn(beBlockOK))) then exit;
  1252.  
  1253.     if ToPrn then begin
  1254.       FName := 'LPT1';
  1255.       Inc(FName[4], Pred(beLPT));
  1256.     end
  1257.     else begin
  1258.       FName := '';
  1259.       if not beGetFileName(epMessage+mcBlockWrite, emBlockWrite,
  1260.                            FName, True, False) then
  1261.         Exit;
  1262.     end;
  1263.  
  1264.     Assign(F, FName);
  1265.     Rewrite(F);
  1266.     I := IOResult;
  1267.     if I <> 0 then begin
  1268.       GotError(epNonFatal+I, emOpenError);
  1269.       Close(F);
  1270.       I := IOResult;
  1271.       Exit;
  1272.     end
  1273.     else if HandleIsConsole(FHandle) then begin
  1274.       GotError(epNonFatal+ecNotToScreen, emNotToScreen);
  1275.       Exit;
  1276.     end;
  1277.  
  1278.     if NOT beStoreBlock(TmpList) then exit;
  1279.     with TmpList do begin
  1280.       if Size = 0 then exit;
  1281.       P := LinePtr(Head);
  1282.       while P <> nil do begin
  1283.         WriteLn(F,P^.lnReturn);
  1284.         if IOResult <> 0 then begin
  1285.           GotError(epNonFatal+ecDeviceWrite, 'Error writing block');
  1286.           P := nil;
  1287.         end
  1288.         else
  1289.           P := LinePtr(P^.dlNext);
  1290.       end;
  1291.       Close(F);  if IOResult = 0 then ;
  1292.       beInformation(0,'');
  1293.     end;
  1294.   end;
  1295.  
  1296.   procedure BigEditor.beIndentBlock(AddSp : Boolean);
  1297.   var P : LinePtr;
  1298.  
  1299.     function CursorInBlock : Boolean;
  1300.     var N : LinePtr;
  1301.     begin
  1302.       CursorInBlock := True;
  1303.       N := BkTop.Line;
  1304.       while N <> LinePtr(BkBot.Line^.dlNext) do begin
  1305.         if N = CurLine then exit;
  1306.         N := LinePtr(N^.dlNext);
  1307.       end;
  1308.       CursorInBlock := False;
  1309.     end;
  1310.  
  1311.   begin
  1312.     beCheckBlock;
  1313.     if (NOT(beOptionsAreOn(beBlockOK))) or
  1314.        (NOT(beOptionsAreOn(beBlockOn))) then begin
  1315.       GotError(epNonFatal+ecNoBlock,'No block defined');
  1316.       exit;
  1317.     end;
  1318.     if NOT(CursorInBlock) then exit;
  1319.     P := BkTop.Line;
  1320.     if P = BkBot.Line then exit;
  1321.  
  1322.     Tmp := P^.lnReturn;
  1323.     if P^.lnLen > 0 then begin
  1324.       if AddSp then begin
  1325.         Insert(CharStr(' ',DefBlockIndent),Tmp,BkTop.Col);
  1326.         if BkTop.Col > 1 then Inc(BkTop.Col,DefBlockIndent);
  1327.       end
  1328.       else begin
  1329.         Delete(Tmp,BkTop.Col,DefBlockIndent);
  1330.         if BkTop.Col > DefBlockIndent then
  1331.           Dec(BkTop.Col,DefBlockIndent)
  1332.         else
  1333.           BkTop.Col := 1;
  1334.       end;
  1335.       P^.lnUpdate(Tmp);
  1336.     end;
  1337.  
  1338.     P := LinePtr(P^.dlNext);
  1339.     while (P <> NIL) and (P <> BkBot.Line) do begin
  1340.       Tmp := P^.lnReturn;
  1341.       if P^.lnLen > 0 then begin
  1342.         if AddSp then
  1343.           Insert(CharStr(' ',DefBlockIndent),Tmp,1)
  1344.         else
  1345.           Delete(Tmp,1,DefBlockIndent);
  1346.         P^.lnUpdate(Tmp);
  1347.       end;
  1348.       P := LinePtr(P^.dlNext);
  1349.     end;
  1350.  
  1351.     if (P <> NIL) and (P^.lnLen > 0) then begin
  1352.       Tmp := P^.lnReturn;
  1353.       if (AddSp) then begin
  1354.         if (BkBot.Col > 0) then begin
  1355.           Insert(CharStr(' ',DefBlockIndent),Tmp,1);
  1356.           Inc(BkBot.Col,DefBlockIndent);
  1357.         end;
  1358.       end
  1359.       else begin
  1360.         Delete(Tmp,1,DefBlockIndent);
  1361.         if BkBot.Col >= DefBlockIndent then
  1362.           Dec(BkBot.Col,DefBlockIndent)
  1363.         else
  1364.           BkBot.Col := 0;
  1365.       end;
  1366.       P^.lnUpdate(Tmp);
  1367.     end;
  1368.     if AddSp then
  1369.       beCursorRight(DefBlockIndent)
  1370.     else
  1371.       beCursorLeft(DefBlockIndent);
  1372.     beForceRedraw := True;
  1373.     SetLongFlag(beOptions,beModified);
  1374.   end;
  1375.  
  1376.   procedure BigEditor.beBlockWord;
  1377.   var P : LinePtr;
  1378.       W,X : Integer;
  1379.   begin
  1380.     W := COfs+XOfs;
  1381.     Tmp := TrimTrail(CurLine^.lnReturn);
  1382.     if W > Length(Tmp) then exit;
  1383.     if Tmp[w] = ' ' then begin
  1384.         {find the start of the next word}
  1385.       while (W <= Length(Tmp)) and (Tmp[w] = ' ') do
  1386.         Inc(W);
  1387.       if W > Length(Tmp) then exit;
  1388.     end
  1389.     else
  1390.         {find the start of the current word}
  1391.       while (W > 1) and (Tmp[w-1] <> ' ') do Dec(W);
  1392.     BkTop.Line := CurLine;
  1393.     BkTop.Col := W;
  1394.       {find the end of the current word}
  1395.     while (W <= Length(Tmp)) and (Tmp[w+1] <> ' ') do
  1396.       Inc(W);
  1397.     BkBot.Line := CurLine;
  1398.     BkBot.Col := W;
  1399.     beClearBlocking;
  1400.     CurLine^.lnFlagsOn(IsBlocked);
  1401.     beOptionsOn(beBlockOn);
  1402.     beForceRedraw := True;
  1403.   end;
  1404.  
  1405.   procedure BigEditor.beChangeCaseBlock(Cmd : Byte);
  1406.     {-Change the case of all characters in block or of character at cursor}
  1407.   var
  1408.     P : LinePtr;
  1409.  
  1410.     function ToggleCase(Ch : Char) : Char;
  1411.       {-Toggle the case of the specified character}
  1412.     var
  1413.       NewCh : Char;
  1414.     begin
  1415.       NewCh := UpCase(Ch);
  1416.       if NewCh <> Ch then
  1417.         ToggleCase := NewCh
  1418.       else
  1419.         ToggleCase := Locase(Ch);
  1420.     end;
  1421.  
  1422.     procedure FixChar(var Ch : Char);
  1423.       {-Fix the case of Ch based on the user's command}
  1424.     begin
  1425.       if Ch > ' ' then
  1426.         case Cmd of
  1427.           ccBlkUCase : Ch := UpCase(Ch);
  1428.           ccBlkLCase : Ch := LoCase(Ch);
  1429.           ccBlkTCase : Ch := ToggleCase(Ch);
  1430.         end;
  1431.     end;
  1432.  
  1433.     procedure FixLine(P : LinePtr; Start, Stop : Integer);
  1434.     var
  1435.       TLen : Byte;
  1436.       I : Integer;
  1437.     begin
  1438.       TLen := P^.lnLen;
  1439.       for I := Start to Stop do
  1440.         if I <= TLen then
  1441.           FixChar(P^.St^[i]);
  1442.     end;
  1443.  
  1444.   begin
  1445.     if (LongFlagIsSet(beOptions, beBlockOn)) and
  1446.        (beLineInBlock(CurLine)) then begin
  1447.       if BkTop.Line = BkBot.Line then
  1448.         FixLine(CurLine,BkTop.Col,BkBot.Col)
  1449.       else begin
  1450.         P := BkTop.Line;
  1451.         FixLine(P,BkTop.Col,P^.lnLen);
  1452.         IncPtr(P,1);
  1453.         while P <> BkBot.Line do begin
  1454.           FixLine(P,1,P^.lnLen);
  1455.           IncPtr(P,1);
  1456.         end;
  1457.         FixLine(P,1,BkBot.Col);
  1458.         beForceRedraw := True;
  1459.       end;
  1460.       SetLongFlag(beOptions,beModified);
  1461.     end
  1462.     else if (COfs+COfs <= CurLine^.lnLen) then begin
  1463.       {change the case of the character at the cursor}
  1464.       FixChar(CurLine^.St^[COfs+XOfs]);
  1465.       SetLongFlag(beOptions,beModified);
  1466.     end;
  1467.   end;
  1468.  
  1469.   procedure BigEditor.beCopyToClipboard;
  1470.   begin
  1471.     if beStoreBlock(Clipboard) then begin
  1472.       beOptionsOff(beBlockOn);
  1473.       beForceRedraw := True;
  1474.     end;
  1475.   end;
  1476.  
  1477.   procedure BigEditor.beCutToClipboard;
  1478.   begin
  1479.     if beStoreBlock(Clipboard) then begin
  1480.       beDeleteBlock;
  1481.       beForceRedraw := True;
  1482.     end;
  1483.   end;
  1484.  
  1485.   procedure BigEditor.bePasteFromClipboard;
  1486.   begin
  1487.     if Clipboard.Head <> NIL then
  1488.       beInsertBlockAtCursor(Clipboard);
  1489.   end;
  1490.  
  1491. {--------------------- Search/Replace/Reformat stuff -----------------------}
  1492.  
  1493.   procedure BigEditor.beTextSearch(Prompt : Boolean; SearchType : beSearchType);
  1494.   label ExitPoint;
  1495.   var
  1496.     SaveRec : StreamStateRec;
  1497.     SaveIdx : Integer;
  1498.     Hits : Integer;
  1499.     TSrch : String[MaxSearchLen];
  1500.     N : Integer;
  1501.     YN : Byte;
  1502.  
  1503.     procedure ReplaceText(var Cur : String; Repl : String; Start, Len : Integer);
  1504.     begin
  1505.       Delete(Cur,Start,Len);
  1506.       Insert(Repl,Cur,Start);
  1507.     end;
  1508.  
  1509.     function NextMatch(StartLine : LinePtr; Srch : String) : LinePtr;
  1510.     var P : LinePtr;
  1511.         T : String;
  1512.     begin
  1513.       NextMatch := NIL;
  1514.       P := StartLine;
  1515.       if P <> NIL then begin
  1516.         if NoCase then
  1517.           Tmp := StUpcase(P^.lnReturn)
  1518.         else
  1519.           Tmp := P^.lnReturn;
  1520.         if Backwards then begin
  1521.           while P <> NIL do begin
  1522.             while SaveIdx >= 1 do begin
  1523.               if Srch[1] = Tmp[SaveIdx] then begin     {possible match}
  1524.                 T := Copy(Tmp,SaveIdx,Length(Srch));
  1525.                 if T = Srch then begin                 {positive match}
  1526.                   NextMatch := P;
  1527.                   exit;
  1528.                 end;
  1529.               end;
  1530.               Dec(SaveIdx);
  1531.             end;
  1532.             P := LinePtr(EList.Prev(P));
  1533.             if P <> NIL then begin
  1534.               Dec(CurTopIdx);
  1535.               beStatusProc(@Self);
  1536.               SaveIdx := P^.lnLen;
  1537.               if NoCase then
  1538.                 Tmp := StUpcase(P^.lnReturn)
  1539.               else
  1540.                 Tmp := P^.lnReturn;
  1541.             end;
  1542.           end;
  1543.         end
  1544.         else begin
  1545.           while P <> NIL do begin
  1546.             while SaveIdx <= Length(Tmp) do begin
  1547.               if Srch[1] = Tmp[SaveIdx] then begin     {possible match}
  1548.                 T := Copy(Tmp,SaveIdx,Length(Srch));
  1549.                 if T = Srch then begin                 {positive match}
  1550.                   NextMatch := P;
  1551.                   exit;
  1552.                 end;
  1553.               end;
  1554.               Inc(SaveIdx);
  1555.             end;
  1556.             P := LinePtr(EList.Next(P));
  1557.             if P <> NIL then begin
  1558.               Inc(CurTopIdx);
  1559.               beStatusProc(@Self);
  1560.               SaveIdx := 1;
  1561.               if NoCase then
  1562.                 Tmp := StUpcase(P^.lnReturn)
  1563.               else
  1564.                 Tmp := P^.lnReturn;
  1565.             end;
  1566.           end;
  1567.         end;
  1568.       end;
  1569.     end;
  1570.  
  1571.   begin
  1572.       {if a reSearch and no prev search performed, quit}
  1573.     if (NOT(Prompt)) and (SearchType = bescSearch) and (beSearchLine = NIL) then
  1574.       exit;
  1575.  
  1576.     if (Prompt) then begin
  1577.       if NOT beGetString(0,'Search for: ',False,False,MaxSearchLen,beSearchSt) then
  1578.         exit;
  1579.  
  1580.       if (SearchType = bescReplace) then begin
  1581.         if NOT beGetString(0,'Replace with: ',False,False,MaxSearchLen,beReplaceSt) then
  1582.           exit;
  1583.       end;
  1584.  
  1585.       if NOT beGetString(0,'Options: ',True,True,MaxSearchOptions,beOptionSt) then
  1586.         exit;
  1587.       beReplacements := 0;
  1588.       NoCase := False;
  1589.       Backwards := False;
  1590.       NoConfirm := False;
  1591.       BlockOnly := False;
  1592.       Global := False;
  1593.       for N := 1 to Length(beOptionSt) do
  1594.         case Upcase(beOptionSt[N]) of
  1595.           beBackward  : Backwards := True;
  1596.           beNoCase    : NoCase := True;
  1597.           beNoConfirm : NoConfirm := True;
  1598.           beBlockOnly : BlockOnly := True;
  1599.           beGlobal    : Global := Prompt and not(LongFlagIsSet(beOptions,beNoRepeatGlobal));
  1600.         end;
  1601.     end;
  1602.  
  1603.     beSaveStreamState(SaveRec,False);
  1604.     SetLongFlag(beOptions,beSearching);
  1605.  
  1606.     if NoCase then
  1607.       TSrch := StUpCase(beSearchSt)
  1608.     else
  1609.       TSrch := beSearchSt;
  1610.  
  1611.     if Backwards then
  1612.       ClearLongFlag(beOptions,beHighlightBack)
  1613.     else
  1614.       SetLongFlag(beOptions,beHighlightBack);
  1615.  
  1616.     beSearchLine := CurLine;
  1617.     if Backwards then
  1618.       SaveIdx := COfs+XOfs-1
  1619.     else
  1620.       SaveIdx := COfs+XOfs;
  1621.  
  1622.       {adjust so Curline is the top-of-screen}
  1623.     CurTopIdx := CurTopIdx+CurLineOfs;
  1624.  
  1625.     if (Prompt) and (Global) then begin
  1626.       if Backwards then begin
  1627.         beSearchLine := LinePtr(EList.Tail);
  1628.         CurTopIdx := EList.Size;
  1629.         SaveIdx := beSearchLine^.lnLen;
  1630.       end
  1631.       else begin
  1632.         beSearchLine := LinePtr(EList.Head);
  1633.         CurTopIdx := 1;
  1634.         SaveIdx := 1;
  1635.       end;
  1636.     end;
  1637.     YN := beYes;
  1638.     Hits := 0;
  1639.  
  1640.     while True do begin
  1641.       CurLineOfs := 0;
  1642.       beSearchLine := NextMatch(beSearchLine,TSrch);
  1643.       if (beSearchLine = NIL) or
  1644.          ((BlockOnly) and (NOT(beLineInBlock(beSearchLine)))) then begin
  1645.         GotError(epNonFatal+ecStringNotFound,'No match found');
  1646.         goto ExitPoint;
  1647.       end;
  1648.       Inc(Hits);
  1649.  
  1650.         {make it displayable}
  1651.       CurLine := beSearchLine;
  1652.       CurTop := CurLine;
  1653.       CurLineOfs := 0;
  1654.       COfs := 1;
  1655.       XOfs := 0;
  1656.         {try to center the line in the screen}
  1657.       while (CurTop^.dlPrev <> NIL) and (CurLineOfs < (Height div 2)) do begin
  1658.         CurTop := LinePtr(EList.Prev(CurTop));
  1659.         Dec(CurTopIdx);
  1660.         Inc(CurLineOfs);
  1661.       end;
  1662.         {position the cursor}
  1663.       if Backwards then
  1664.         beCursorRight(SaveIdx-1)
  1665.       else
  1666.         beCursorRight(SaveIdx+Length(beSearchSt)-1);
  1667.       beForceRedraw := True;
  1668.       beInformation(0,'');
  1669.       SetLongFlag(beOptions,beShowMkrs);
  1670.       beUpdateContents;
  1671.       beSaveStreamState(SaveRec,False);
  1672.  
  1673.       if SearchType = bescSearch then begin
  1674.         while NOT cwCmdPtr^.cpKeyPressed do ;
  1675.         goto ExitPoint;
  1676.       end
  1677.       else begin
  1678.         if NOT NoConfirm then begin
  1679.           YN := beYesNo(0,'Replace?',beNo,True);
  1680.           NoConfirm := (YN = beAll);
  1681.           if (YN = beQuit) then
  1682.             goto ExitPoint;
  1683.         end;
  1684.         if YN <> beNo then begin
  1685.           Tmp := CurLine^.lnReturn;
  1686.           ReplaceText(Tmp,beReplaceSt,SaveIdx,Length(beSearchSt));
  1687.           CurLine^.lnUpdate(Tmp);
  1688.           inc(beReplacements);
  1689.           ClearLongFlag(beOptions,beShowMkrs);
  1690.           beForceRedraw := True;
  1691.           beUpdateContents;
  1692.         end;
  1693.         CurTopIdx := CurTopIdx+CurLineOfs;
  1694.         if Backwards then
  1695.           Dec(SaveIdx)
  1696.         else if Length(beReplaceSt) > Length(beSearchSt) then
  1697.           Inc(SaveIdx,Length(beReplaceSt))
  1698.         else
  1699.           Inc(SaveIdx,Length(beSearchSt));
  1700.       end;
  1701.     end;
  1702.  
  1703. ExitPoint:
  1704.     beRestoreStreamState(SaveRec,False);
  1705.     if beReplacements > 0 then
  1706.       SetLongFlag(beOptions,beModified);
  1707.     if (SearchType = bescReplace) and (beReplacements > 0) then
  1708.       beInformation(0,'  Replacements: '+Long2Str(beReplacements));
  1709.     ClearLongFlag(beOptions,beSearching);
  1710.     beUpdateContents;
  1711.   end;
  1712.  
  1713.   procedure BigEditor.beReformatPara;
  1714.   label BrkOut;
  1715.   var B : Byte;
  1716.       P,N : LinePtr;
  1717.       S : String;
  1718.   begin
  1719.     if NOT beOptionsAreOn(beWordWrap) then exit;
  1720.     SetLongFlag(beOptions,beReformatting);
  1721.  
  1722.     while (CurLine^.dlNext <> NIL) and (CurLine^.St^ = '') do
  1723.       beLineDown(1);
  1724.     if CurLine^.dlNext = NIL then exit;
  1725.     B := beOfsWhite(CurLine);
  1726.     P := CurLine;
  1727.  
  1728.       {run the loop}
  1729.     while (P <> NIL) and (P^.lnLen > 0) do begin
  1730.       while (P^.lnLen <= Margin+1) and (LinePtr(P^.dlNext)^.lnLen > 0) do begin
  1731.         N := LinePtr(P^.dlNext);
  1732.         if N = nil then goto BrkOut;
  1733.         Tmp := N^.lnReturn;
  1734.         Tmp := ' '+Trim(Tmp);
  1735.         P^.lnUpdate(P^.lnReturn+Tmp);
  1736.         EList.Delete(N);
  1737.       end;
  1738.       WordWrap(P^.lnReturn,Tmp,S,Margin,False);
  1739.       Tmp := Trim(Tmp);
  1740.       if B > 0 then
  1741.         Insert(CharStr(' ',B),Tmp,1);
  1742.       P^.lnUpdate(Tmp);
  1743.       S := Trim(S);
  1744.       if S <> '' then begin
  1745.         if B > 0 then
  1746.           Insert(CharStr(' ',B),S,1);
  1747.         New(N,Init(S));
  1748.         EList.Place(N,P);
  1749.       end;
  1750.       P := LinePtr(P^.dlNext);
  1751.     end;
  1752. BrkOut:
  1753.     CurLine := P;
  1754.     beRealignDown;
  1755.     beCursorHome;
  1756.     beCursorRight(CurLine^.lnLen);
  1757.     ClearLongFlag(beOptions,beReformatting);
  1758.     SetLongFlag(beOptions,beModified);
  1759.  
  1760.     beCheckBlock;
  1761.     if beOptionsAreOn(beBlockOK) then begin
  1762.       beClearBlocking;
  1763.       beResetMarkers(False);
  1764.       beOptionsOff(beBlockOn);
  1765.     end;
  1766.     beForceRedraw := True;
  1767.   end;
  1768.  
  1769.   procedure BigEditor.beReformatGlobally;
  1770.   var S : StreamStateRec;
  1771.   begin
  1772.     beSaveStreamState(S,False);
  1773.     while CurLine^.dlNext <> nil do begin
  1774.       beReformatPara;
  1775.       beUpdateContents;
  1776.     end;
  1777.     beRestoreStreamState(S,False);
  1778.   end;
  1779.  
  1780.   procedure BigEditor.beCenterLine;
  1781.   var
  1782.     StLen : Byte absolute Current;
  1783.     I, J, Delta, Len : Integer;
  1784.   begin
  1785.     if StLen = 0 then
  1786.       Exit;
  1787.  
  1788.     {find the first non-blank}
  1789.     I := 1;
  1790.     while Current[I] = ' ' do
  1791.       Inc(I);
  1792.  
  1793.     {length of actual text in string}
  1794.     Len := Succ(StLen-I);
  1795.  
  1796.     {can it be centered?}
  1797.     if Len >= Margin then begin
  1798.       if I > 1 then begin
  1799.         {can't center it, but we can move it to the left margin}
  1800.         Delete(Current, 1, Pred(I));
  1801.         beCharsInserted(CurLine, -Pred(I));
  1802.  
  1803.         {adjust cursor}
  1804.         if COfs+XOfs >= I then
  1805.           beCursorLeft(Pred(I))
  1806.         else
  1807.           beCursorHome;
  1808.       end;
  1809.     end
  1810.     else begin
  1811.       {calculate new starting column}
  1812.       J := Succ((Margin-Len) shr 1);
  1813.       Delta := J-I;
  1814.  
  1815.       if Delta > 0 then begin
  1816.         {insert extra spaces at beginning of line}
  1817.         Insert(CharStr(' ', Delta), Current, 1);
  1818.         beCharsInserted(CurLine, Delta);
  1819.  
  1820.           {adjust cursor}
  1821.         beCursorRight(Delta);
  1822.       end
  1823.       else if Delta < 0 then begin
  1824.         {delete extra spaces at beginning of line}
  1825.         Delete(Current, 1, -Delta);
  1826.         beCharsInserted(CurLine, -Delta);
  1827.  
  1828.         {adjust cursor}
  1829.         if COfs+XOfs > Abs(Delta) then
  1830.           beCursorRight(Delta)
  1831.         else
  1832.           beCursorHome;
  1833.       end;
  1834.     end;
  1835.     CurLine^.lnUpdate(Current);
  1836.     SetLongFlag(beOptions,beModified);
  1837.   end;
  1838.